using System;
using System.Collections.Generic;
using System.Xml;
// using System.Xml.XPath;
using System.Globalization;

namespace MobileTDL
{
	abstract public class DocumentBase
	{
		private XmlDocument _doc;

		protected DocumentBase()
		{
		}

		protected DocumentBase(XmlDocument doc)
		{
			Doc = doc;
		}

		protected DocumentBase(string fileName)
		{
			Doc = new XmlDocument();
			Doc.Load(fileName);
		}

		public XmlDocument Doc
		{
			get { return _doc; }
			set { _doc = value; }
		}
	}

	abstract public class ElementBase : DocumentBase
	{
		private XmlElement _element;

		protected ElementBase()
		{
		}

		protected ElementBase(XmlDocument doc, XmlElement element)
			: base(doc)
		{
			Element = element;
		}

		public XmlElement Element
		{
			get { return _element; }
			set { _element = value; }
		}

		protected XmlAttribute GetAttribute(string name)
		{
			XmlAttribute attribute;
			if (Element.HasAttribute(name)) attribute = Element.GetAttributeNode(name);
			else
			{
				attribute = Doc.CreateAttribute(name);
				Element.Attributes.Append(attribute);
			}
			return attribute;
		}

		protected Int32? ParseInt32(string value)
		{
			Int32? result;
			if (value.Length > 0)
			{
				try
				{
					result = Int32.Parse(value, CultureInfo.InvariantCulture);
				}
				catch (FormatException)
				{
					result = null;
				}
			}
			else result = null;
			return result;
		}

		protected DateTime? ParseOADate(string value)
		{
			DateTime? result;
			if (value.Length > 0)
			{
				try
				{
					result = DateTime.FromOADate(double.Parse(value, CultureInfo.InvariantCulture));
				}
				catch (FormatException)
				{
					result = null;
				}
			}
			else result = null;
			return result;
		}
	}

	abstract public class ElementContainer<TSubElement> : ElementBase
		where TSubElement : ElementBase, new()
	{
		public event EventHandler<ItemEventArgs<TSubElement>> ItemAdded;
		public event EventHandler<ItemEventArgs<TSubElement>> ItemRemoved;
		public event EventHandler<ItemSetEventArgs<TSubElement>> ItemSet;

		private SortType _sortType = SortType.Position;
		private string _subElementName = "";
		private NotifyingList<TSubElement> _items;

		protected ElementContainer(string subElementName)
		{
			SubElementName = subElementName;
		}

		protected ElementContainer(XmlDocument doc, XmlElement element, string subElementName)
			: base(doc, element)
		{
			SubElementName = subElementName;
		}

		public NotifyingList<TSubElement> Items
		{
			get
			{
				if (_items == null)
				{
					Items = new NotifyingList<TSubElement>();
					TSubElement subElementItem;
					foreach (XmlElement subElement in Element.SelectNodes(SubElementName))
					{
						subElementItem = new TSubElement();
						subElementItem.Doc = Doc;
						subElementItem.Element = subElement;
						_items.Add(subElementItem);
					}
				}
				return _items;
			}
			private set
			{
				if (_items != null)
				{
					_items.ItemAdded -= new EventHandler<ItemEventArgs<TSubElement>>(_items_ItemAdded);
					_items.ItemRemoved -= new EventHandler<ItemEventArgs<TSubElement>>(_items_ItemRemoved);
					_items.ItemSet -= new EventHandler<ItemSetEventArgs<TSubElement>>(_items_ItemSet);
				}
				_items = value;
				if (_items != null)
				{
					_items.ItemAdded += new EventHandler<ItemEventArgs<TSubElement>>(_items_ItemAdded);
					_items.ItemRemoved += new EventHandler<ItemEventArgs<TSubElement>>(_items_ItemRemoved);
					_items.ItemSet += new EventHandler<ItemSetEventArgs<TSubElement>>(_items_ItemSet);
				}
			}
		}

		public SortType SortType
		{
			get { return _sortType; }
			set { _sortType = value; }
		}

		public string SubElementName
		{
			get { return _subElementName; }
			set { _subElementName = value; }
		}

		virtual protected void OnItemAdded(ItemEventArgs<TSubElement> args)
		{
			if (ItemAdded != null) ItemAdded(this, args);
		}

		virtual protected void OnItemSet(ItemSetEventArgs<TSubElement> args)
		{
			if (ItemSet != null) ItemSet(this, args);
		}

		virtual protected void OnItemRemoved(ItemEventArgs<TSubElement> args)
		{
			if (ItemRemoved != null) ItemRemoved(this, args);
		}

		void _items_ItemAdded(object sender, ItemEventArgs<TSubElement> args)
		{
			if (args.Item.Element.ParentNode != Element) Element.AppendChild(args.Item.Element);
			OnItemAdded(args);
		}

		void _items_ItemRemoved(object sender, ItemEventArgs<TSubElement> args)
		{
			if (args.Item.Element.ParentNode == Element) Element.RemoveChild(args.Item.Element);
			OnItemRemoved(args);
		}

		void _items_ItemSet(object sender, ItemSetEventArgs<TSubElement> args)
		{
			if (args.OldItem.Element.ParentNode == Element) Element.RemoveChild(args.OldItem.Element);
			if (args.NewItem.Element.ParentNode != Element) Element.AppendChild(args.NewItem.Element);
			OnItemSet(args);
		}
	}
}
